<?php

/* ========================================================================= */
/* This file is part of the HypnoPHP Framework Library                       */
/* Copyright (c) 2009-2010, Radu Buzea                                       */
/* ========================================================================= */

/**
* @author Radu Buzea
* @copyright Copyright (c) 2009-2010, Radu Buzea (www.hypnosis.ro)
* @license GNU Lesser General Public License (www.gnu.org/copyleft/lesser.html)
* @package HypnoPHP
* @category Core
* @version 1.0.3
*/

// ============================================================================
// Interfaces: IBaseDbQuery
// ============================================================================

interface IBaseDbQuery
{
	public function isReady();
	public function select($columns, $target_table = null, $as_name = null, $schema = null);
	public function union($columns, $target_table = null, $as_name = null, $schema = null);
	public function distinct($flag = true);
	public function from($target_table, $as_name = null, $schema = null);
	public function into($table_name, $schema = null);
	public function join($mode = 0, $target_table, $condition, $as_name = null, $scema = null);
	public function innerJoin($target_table, $condition, $as_name = null, $scema = null);
	public function leftJoin($target_table, $condition, $as_name = null, $scema = null);
	public function rightJoin($target_table, $condition, $as_name = null, $scema = null);
	public function fullJoin($target_table, $condition, $as_name = null, $scema = null);
	public function crossJoin($target_table, $condition, $as_name = null, $scema = null);
	public function naturalJoin($target_table, $condition, $as_name = null, $scema = null);
	public function where($column, $operator, $value);
	public function orWhere($column, $operator, $value);
	public function having($column_or_aggregate, $operator, $value);
	public function orHaving($column_or_aggregate, $operator, $value);
	public function orderBy($column, $descending = false);
	public function groupBy($column, $descending = false);
	public function limit($param1 = 0, $param2 = null);
	public function delete($target_table, $schema = null);
	public function insert($data, $target_table, $schema = null);
	public function update($data, $target_table, $schema = null);
	public function quikSelect($columns, $target_table_schema, $conditions = null, $limit = null);
	public function quikUpdate($columns_data, $target_table_schema, $conditions = null, $limit = null);
	public function quikInsert($columns_data, $target_table_schema);
	public function quikDelete($target_table_schema, $conditions = null);
	public function quickWhere($conditions);
	public function execute();
}

# #############################################################################

define('DBQUERY_INNER_JOIN',   0);
define('DBQUERY_LEFT_JOIN',    1);
define('DBQUERY_RIGHT_JOIN',   2);
define('DBQUERY_FULL_JOIN',    3);
define('DBQUERY_CROSS_JOIN',   4);
define('DBQUERY_NATURAL_JOIN', 5);

// ============================================================================
// Abstract class: HBaseDbQuery
// ============================================================================

abstract class HBaseDbQuery extends HbaseObject implements IBaseDbQuery
{

	protected $__ready_state = 0;
	protected $__database_object = null;
	protected $__query = array();
	protected $__query_key = '';
	protected $__union_index = 0;
	protected $__last_action = '';
	protected $__join_keys = array(
		DBQUERY_INNER_JOIN   => 'INNER_JOIN',
		DBQUERY_LEFT_JOIN    => 'LEFT_JOIN',
		DBQUERY_RIGHT_JOIN   => 'RIGHT_JOIN',
		DBQUERY_FULL_JOIN    => 'FULL_JOIN',
		DBQUERY_CROSS_JOIN   => 'CROSS_JOIN',
		DBQUERY_NATURAL_JOIN => 'NATURAL_JOIN',
	);
	protected $__allowed_where_value_types = array(
		"boolean" => 1,
		"integer" => 2,
		"double"  => 3,
		"float"   => 4,
		"string"  => 5,
		"null"    => 6,
	);

	# ###########################################################################

	/**
	* Class construct
	*
	* @param object (optional) The associated database object (HBaseDb)
	* @return HBaseDbQuery
	*/
	public function __construct()
	{
		$this->__database_object = null;
		if (func_num_args() == 1) {
			$param = func_get_arg(0);
			if (is_object($param) && is_subclass_of($param, 'HBaseDb')) {
				$this->__database_object = $param;
			}
		}
		parent::__construct();
	}

	# ###########################################################################

	/**
	* Database object property getter method
	*
	* @return object (HBaseDb) or null
	*/
	protected function __get_database_object()
	{
		return $this->__database_object;
	}

	# ###########################################################################

	/**
	* Database object property setter method
	*
	* @param object $param HBaseDb
	* @return void
	*/
	protected function __set_database_object($param = null)
	{
		if (is_null($param)) {
			$this->__ready_state = 0;
		} else if (is_subclass_of($param, 'HBaseDb')) {
			$this->__database_object = $param;
			$this->__ready_state = 0;
		}
	}

	# ###########################################################################

	/**
	* Get the database object state
	*
	*	@return bool
	*/
	public function isReady()
	{
		if ($this->__ready_state > 0) { return ($this->__ready_state == 1); }
		$result = true;
		if (is_null($this->__database_object) || !is_object($this->__database_object) ||
			!is_subclass_of($this->__database_object, 'HBaseDb')) { $result = false; }
		$this->__ready_state = $result ? 1 : 2;
		return $result;
	}

	# ###########################################################################

	/**
	* Convert a delimietd string into an array
	* @param mixed $param (array or string)
	* @return array
	*/
	public function queryArrayParam($param)
	{
		if (is_string($param)) {
			$table_name = trim($param);
			if (strstr($param, ',')) { $param = explode(',', $param); }
			else if (strstr($param, ';')) { $param = explode(',', $param); }
			else { $param = array($param); }
		}
		if (!is_array($param)) { $param = array(); }
		return $param;
	}

	# ###########################################################################

	/**
	* Internal method - set the query mode
	*
	* @param string $query_key
	* @return void
	*/
	protected function __queryMode($query_key)
	{
		if (!is_string($query_key) || trim($query_key) == '') { return false; }
		$query_key = trim(strtoupper($query_key));
		$__query_modes = array(
			'SELECT' => 1,
			'DELETE' => 2,
			'INSERT' => 3,
			'UPDATE' => 4,
		);
		if (!isset($__query_modes[$query_key])) {
			if ($query_key != 'UNION_SELECT_' . $this->__union_index) { return false; }
		}
		$this->__query_key = $query_key;
		if (!isset($this->__query[$this->__query_key])) {
			if ($query_key == 'UNION_SELECT_' . $this->__union_index) {
				$this->__query['UNION_SELECT_' . $this->__union_index] = array();
			} else {
				$this->__query = array($this->__query_key => array());
			}
		}
	}

	# ###########################################################################

	/**
	* Prepare the SQL SELECT statement
	*
	* @param array $columns A list of columns (fields)
	* @param string $target_table The database table name
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function select($columns, $target_table = null, $as_name = null, $schema = null)
	{
		$this->__queryMode('SELECT');
		$qkey = $this->__query_key;
		$columns = $this->queryArrayParam($columns);
		if (!is_null($as_name)) { $as_name = $this->queryArrayParam($as_name); }
		if (count($columns) == 0) { $columns = array("*"); }
		// Check the SELECT FIELDS query section
		if (!isset($this->__query[$qkey]['FIELDS']) || !is_array($this->__query[$qkey]['FIELDS'])) {
			$this->__query[$qkey]['FIELDS'] = array();
		}
		// Check an prepare the target table name and the schema name
		$pre_column = '';
		if (is_string($target_table)) {
			$target_table = trim($target_table);
			if ($target_table != '') { $pre_column .= $target_table . '.'; }
		}
		if (is_string($schema)) {
			$schema = trim($schema);
			if ($schema != '') { $pre_column .= $schema . '.'; }
		}
		// Adding field names in SELECT query part
		foreach ($columns as $key => $column) {
			if (is_string($column)) {
				$column = $pre_column . trim($column);
				if (is_array($as_name) && isset($as_name[$key])) { $column_value = $as_name[$key]; }
				else { $column_value = ''; }
				if ($column != $pre_column && !isset($this->__query[$qkey]['FIELDS'][$column])) {
					$this->__query[$qkey]['FIELDS'][$column] = $column_value;
				}
			}
		}
		$this->__last_action = 'SELECT';
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare the SQL UNION statement
	*
	* @param array $columns A list of columns (fields)
	* @param string $target_table The database table name
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function union($columns, $target_table = null, $as_name = null, $schema = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT') {
			$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
			return $this;
		}
		$this->__union_index++;
		$qkey = 'UNION_SELECT_' . $this->__union_index;

		if ($this->__queryMode($qkey) === false) { return $this; }

		$columns = $this->queryArrayParam($columns);
		if (!is_null($as_name)) { $as_name = $this->queryArrayParam($as_name); }
		if (count($columns) == 0) { $columns = array("*"); }
		// Check the UNION SELECT FIELDS query section
		if (!isset($this->__query[$qkey]['FIELDS']) || !is_array($this->__query[$qkey]['FIELDS'])) {
			$this->__query[$qkey]['FIELDS'] = array();
		}
		// Check an prepare the target table name and the schema name
		$pre_column = '';
		if (is_string($target_table)) {
			$target_table = trim($target_table);
			if ($target_table != '') { $pre_column .= $target_table . '.'; }
		}
		if (is_string($schema)) {
			$schema = trim($schema);
			if ($schema != '') { $pre_column .= $schema . '.'; }
		}
		// Adding field names in UNION SELECT query part
		foreach ($columns as $key => $column) {
			if (is_string($column)) {
				$column = $pre_column . trim($column);
				if (is_array($as_name) && isset($as_name[$key])) { $column_value = $as_name[$key]; }
				else { $column_value = ''; }
				if ($column != $pre_column && !isset($this->__query[$qkey]['FIELDS'][$column])) {
					$this->__query[$qkey]['FIELDS'][$column] = $column_value;
				}
			}
		}
		$this->__last_action = 'SELECT';
		return $this;
	}

	# ###########################################################################

	/**
	* Set the SQL SELECT DISTINCT statement
	*
	* @param bool $flag
	* @return object (this) HBaseDbQuery
	*/
	public function distinct($flag = true)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
			return $this;
		}
		$this->__query[$qkey]['DISTINCT'] = $flag;
		$this->__last_action = 'DISTINCT';
		return $flag;
	}

	# ###########################################################################

	/**
	* Prepare the SQL FROM statement
	*
	* @param string $target_table The database table name
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function from($target_table, $as_name = null, $schema = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'DELETE' && $qkey != 'SELECT' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in DELETE or SELECT mode", E_USER_WARNING);
			return $this;
		}
		// Check the function arguments
		if (!is_string($target_table) || trim($target_table) == '') {
			$this->addError("Invalid FROM target table name parameter", E_USER_WARNING);
			return $this;
		}
		// Check the SELECT/DELETE FROM query section
		if (!isset($this->__query[$qkey]['FROM']) || !is_array($this->__query[$qkey]['FROM'])) {
			$this->__query[$qkey]['FROM'] = array();
		}
		$target_table = trim($target_table);
		if (is_string($as_name) && $qkey == 'SELECT') { $as_name = trim($as_name); }
		else { $as_name = ''; }
		// Adding target table name in the FROM query part
		if (is_string($schema) && trim($schema) != '') {
			$this->__query[$qkey]['FROM'][] = array(
				'TABLE' => $schema . '.' . $target_table,
				'AS' => $as_name,
			);
		} else {
			$this->__query[$qkey]['FROM'][] = array(
				'TABLE' => $target_table,
				'AS' => $as_name,
			);
		}
		$this->__last_action = 'FROM';
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare the SQL SELECT INTO statement
	*
	* @param string $target_table The database table name
	* @param string $schema (optional)\
	* @return object (this) HBaseDbQuery
	*/
	public function into($target_table, $schema = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT') {
			$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
			return $this;
		}
		// Check the function arguments
		if (!is_string($target_table) || trim($target_table) == '') {
			$this->addError("Invalid INTO target table name parameter", E_USER_WARNING);
			return $this;
		}
		// Adding target table name in the INTO query part
		if (is_string($schema) && trim($schema) != '') {
			$this->__query[$qkey]['INTO'] = $schema . '.' . trim($target_table);
		} else {
			$this->__query[$qkey]['INTO'] = trim($target_table);
		}
		$this->__last_action = 'INTO';
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare the SQL JOIN statement
	*
	* @param integer $mode (DBQUERY_INNER_JOIN, DBQUERY_LEFT_JOIN, DBQUERY_RIGHT_JOIN,
	* DBQUERY_FULL_JOIN, DBQUERY_CROSS_JOIN, DBQUERY_NATURAL_JOIN)
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function join($mode = 0, $target_table, $condition, $as_name = null, $scema = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'DELETE' && $qkey != 'SELECT' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
			return $this;
		}
		// Check the function arguments
		if (!is_string($target_table) || trim($target_table) == '') {
			$this->addError("Invalid JOIN target table name parameter", E_USER_WARNING);
			return $this;
		}
		if (!is_string($condition) || trim($condition) == '') {
			$this->addError("Invalid JOIN condition parameter", E_USER_WARNING);
			return $this;
		}
		// Select JOIN mode key
		if (!isset($this->__join_keys[$mode])) { $join_key = 'INNER_JOIN'; }
		else { $join_key = $this->__join_keys[$mode]; }
		if (!isset($this->__query[$qkey][$join_key]) || !is_array($this->__query[$qkey][$join_key])) {
			$this->__query[$qkey][$join_key] = array();
		}
		// Adding target table name in the JOIN query part
		$i = count($this->__query[$qkey][$join_key]);
		if (is_string($schema) && trim($schema) != '') {
			$this->__query[$qkey][$join_key][$i] = array(
				'TABLE' => $schema . '.' . trim($target_table)
			);
		} else {
			$this->__query[$qkey][$join_key][$i] = array(
				'TABLE' => trim($target_table)
			);
		}
		// Adding JOIN conditions query part
		$this->__query[$qkey][$join_key][$i]['CONDITION'] = trim($condition);
		// Adding JOIN AS query part
		if (is_string($as_name) && trim($as_name) != '') {
			$this->__query[$qkey][$join_key][$i]['AS'] = trim($as_name);
		}
		$this->__last_action = $join_key;
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare the SQL INNER JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function innerJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_INNER_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL LEFT JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function leftJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_LEFT_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL RIGHT JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function rightJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_RIGHT_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL FULL JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function fullJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_FULL_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL CROSS JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function crossJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_CROSS_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL NATURAL JOIN statement
	*
	* @param string $target_table The database table name
	* @param string $condition The JOIN SQL condition statement
	* @param array $as_name (optional) A list of aliases
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function naturalJoin($target_table, $condition, $as_name = null, $scema = null)
	{
		return $this->join(DBQUERY_NATURAL_JOIN, $target_table, $condition, $as_name, $scema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL WHERE statement
	*
	* @param string $column The field name used in the WHERE condition statement
	* @param string $operator The logical operator used in the WHERE condition statement
	* @param mixed $value The value used in the WHERE condition statement
	* @return object (this) HBaseDbQuery
	*/
	public function where($column, $operator, $value)
	{
		$this->__last_action = 'WHERE';
		return $this->__whereHaving(0, $column, $operator, $value, false);
	}

	# ###########################################################################

	/**
	* Prepare the SQL OR WHERE statement
	*
	* @param string $column The field name used in the WHERE condition statement
	* @param string $operator The logical operator used in the WHERE condition statement
	* @param mixed $value The value used in the WHERE condition statement
	* @return object (this) HBaseDbQuery
	*/
	public function orWhere($column, $operator, $value)
	{
		$this->__last_action = 'OR_WHERE';
		return $this->__whereHaving(0, $column, $operator, $value, true);
	}

	# ###########################################################################

	/**
	* Prepare the SQL HAVING statement
	*
	* @param string $column The field name used in the HAVING condition statement
	* @param string $operator The logical operator used in the HAVING condition statement
	* @param mixed $value The value used in the HAVING condition statement
	* @return object (this) HBaseDbQuery
	*/
	public function having($column, $operator, $value)
	{
		$this->__last_action = 'HAVING';
		return $this->__whereHaving(1, $column, $operator, $value, false);
	}

	# ###########################################################################

	/**
	* Prepare the SQL OR HAVING statement
	*
	* @param string $column The field name used in the HAVING condition statement
	* @param string $operator The logical operator used in the HAVING condition statement
	* @param mixed $value The value used in the HAVING condition statement
	* @return object (this) HBaseDbQuery
	*/
	public function orHaving($column, $operator, $value)
	{
		$this->__last_action = 'OR_HAVING';
		return $this->__whereHaving(1, $column, $operator, $value, true);
	}

	# ###########################################################################

	/**
	* Prepare the SQL ORDER BY statement
	*
	* @param string $column The field name used in the ORDER BY statement
	* @param bool $descending (false for ascending order, true for descending order)
	* @return object (this) HBaseDbQuery
	*/
	public function orderBy($column, $descending = false)
	{
		$this->__last_action = 'ORDER_BY';
		return $this->__orderGroupBy(0, $column, $descending);
	}

	# ###########################################################################

	/**
	* Prepare the SQL GROUP BY statement
	*
	* @param string $column The field name used in the GROUP BY condition statement
	* @param bool $descending (false for ascending order, true for descending order)
	* @return object (this) HBaseDbQuery
	*/
	public function groupBy($column, $descending = false)
	{
		$this->__last_action = 'GROUP_BY';
		return $this->__orderGroupBy(1, $column, $descending);
	}

	# ###########################################################################

	/**
	* Prepare the SQL LIMIT statement
	*
	* @param int $param1 The limit starting index or range if $param2 is null
	* @param int $param2 The limit range
	* @return object (this) HBaseDbQuery
	*/
	public function limit($param1 = 0, $param2 = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT' && $qkey != 'UPDATE' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in SELECT or UPDATE mode", E_USER_WARNING);
			return $this;
		}
		if (is_string($param1)) {
			$param1 = trim($param1);
			if ($param1 != '') {
				if (strstr($param1, '.')) { $param1 = explode('.', $param1); }
				else if (strstr($param1, ',')) { $param1 = explode(',', $param1); }
				else if (strstr($param1, ';')) { $param1 = explode(';', $param1); }
				else { $param1 = intval($param1); }
			}
			if (is_array($param1)) {
				foreach ($param1 as $k => $param) { $param1[$k] = intval($param); }
			}
		}
		if (is_array($param1)) {
			$limit = $param1;
			if (isset($limit[0])) { $param1 = intval($limit[0]); }
			if (isset($limit[1])) { $param2 = intval($limit[1]); }

		}
		if (!is_int($param1) || $param1 < 0) {
			$this->addError("Invalid LIMIT first parameter", E_USER_WARNING);
		}
		if (!is_null($param2) && (!is_int($param2) || $param2 < 0)) {
			$this->addError("Invalid LIMIT second parameter", E_USER_WARNING);
		}
		$this->__query[$qkey]['LIMIT'] = array($param1, $param2);
		$this->__last_action = 'LIMIT';
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare the SQL DELETE statement
	*
	* @param string $target_table The database table name
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function delete($target_table, $schema = null)
	{
		$this->__queryMode('DELETE');
		$qkey = $this->__query_key;
		if (is_string($target_table) && trim($target_table) != '') {
			return $this->from($target_table, null, $schema);
		} else {
			return $this;
		}
	}

	# ###########################################################################

	/**
	* Prepare the SQL INSERT statement
	*
	* @param array $data An array with field names as keys and field values
	* @param string $target_table The database table name
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function insert($data, $target_table, $schema = null)
	{
		if (!is_array($data) || count($data) == 0) {
			$this->addError("Invalid data for the INSERT query", E_USER_WARNING);
			return $this;
		}
		$this->__queryMode('INSERT');
		return $this->__insertUpdate($data, $target_table, $schema);
	}

	# ###########################################################################

	/**
	* Prepare the SQL UPDATE statement
	*
	* @param array $data An array with field names as keys and field values
	* @param string $target_table The database table name
	* @param string $schema (optional)
	* @return object (this) HBaseDbQuery
	*/
	public function update($data, $target_table, $schema = null)
	{
		if (!is_array($data) || count($data) == 0) {
			$this->addError("Invalid data for the UPDATE query", E_USER_WARNING);
			return $this;
		}
		$this->__queryMode('UPDATE');
		return $this->__insertUpdate($data, $target_table, $schema);
	}

	# ###########################################################################

	/**
	* Prepare an SQL SELECT statement (one method fast mode)
	*
	* @param array $columns
	* @param string $target_table_schema The database table name with or without schema name
	* @param string $conditions (optional) The SELECT conditions
	* @param mixed $limit Can be integer, array (with tow integer values), string
	* @return object (this) HBaseDbQuery
	*/
	public function quikSelect($columns, $target_table_schema, $conditions = null, $limit = null)
	{
		$columns = $this->queryArrayParam($columns);
		if (!is_string($target_table_schema)) {
			$this->addError("Invalid taregt tabel name for the quick SELECT query", E_USER_WARNING);
			return $this;
		}
		if (strstr($target_table_schema, '.')) {
			list($target_table, $schema) = explode('.', $target_table_schema);
			if (trim($schema) == '') { $schema = null; }
		} else {
			$target_table = $target_table_schema;
			$schema = null;
		}
		$this->select($columns);
		$this->from($target_table, null, $schema);
		$this->__quickWhere($conditions);
		if (is_int($limit) || is_array($limit) || is_string($limit)) { $this->limit($limit); }
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare an SQL UPDATE statement (one method fast mode)
	*
	* @param array $columns_data
	* @param string $target_table_schema The database table name with or without schema name
	* @param string $conditions (optional) The UPDATE conditions
	* @param mixed $limit Can be integer, array (with tow integer values), string
	* @return object (this) HBaseDbQuery
	*/
	public function quikUpdate($columns_data, $target_table_schema, $conditions = null, $limit = null)
	{
		if (!is_array($columns_data)) {
			$this->addError("Invalid fields data for the quick UPDATE query", E_USER_WARNING);
			return $this;
		}
		if (!is_string($target_table_schema)) {
			$this->addError("Invalid taregt tabel name for the quick UPDATE query", E_USER_WARNING);
			return $this;
		}
		if (strstr($target_table_schema, '.')) {
			list($target_table, $schema) = explode('.', $target_table_schema);
			if (trim($schema) == '') { $schema = null; }
		} else {
			$target_table = $target_table_schema;
			$schema = null;
		}
		$this->update($columns_data, $target_table, $schema);
		$this->__quickWhere($conditions);
		if (is_int($limit) || is_array($limit) || is_string($limit)) { $this->limit($limit); }
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare an SQL INSERT statement (one method fast mode)
	*
	* @param array $columns_data
	* @param string $target_table_schema The database table name with or without schema name
	* @return object (this) HBaseDbQuery
	*/
	public function quikInsert($columns_data, $target_table_schema)
	{
		if (!is_array($columns_data)) {
			$this->addError("Invalid fields data for the quick INSERT query", E_USER_WARNING);
			return $this;
		}
		if (!is_string($target_table_schema)) {
			$this->addError("Invalid taregt tabel name for the quick INSERT query", E_USER_WARNING);
			return $this;
		}
		if (strstr($target_table_schema, '.')) {
			list($target_table, $schema) = explode('.', $target_table_schema);
			if (trim($schema) == '') { $schema = null; }
		} else {
			$target_table = $target_table_schema;
			$schema = null;
		}
		$this->insert($columns_data, $target_table, $schema);
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare an SQL DELETE statement (one method fast mode)
	*
	* @param string $target_table_schema The database table name with or without schema name
	* @param string $conditions (optional) The UPDATE conditions
	* @return object (this) HBaseDbQuery
	*/
	public function quikDelete($target_table_schema, $conditions = null)
	{
		if (!is_string($target_table_schema)) {
			$this->addError("Invalid taregt tabel name for the quick INSERT query", E_USER_WARNING);
			return $this;
		}
		if (strstr($target_table_schema, '.')) {
			list($target_table, $schema) = explode('.', $target_table_schema);
			if (trim($schema) == '') { $schema = null; }
		} else {
			$target_table = $target_table_schema;
			$schema = null;
		}
		$this->delete($target_table, $schema);
		$this->__quickWhere($conditions);
		return $this;
	}

	# ###########################################################################

	/**
	* Prepare an SQL WHERE statement (one method fast mode)
	*
	* @param string $conditions The WHERE conditions
	* @return object (this) HBaseDbQuery
	*/
	public function quickWhere($conditions)
	{
		if (!is_string($conditions) || trim($conditions) == '') { return $this; }
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT' && $qkey != 'UPDATE' && $qkey != 'DELETE' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in DELETE, SELECT, or UPDATE mode", E_USER_WARNING);
			return $this;
		}
		$conditions = trim($conditions);
		if (substr(strtoupper($conditions), 0, 5) == 'WHERE') {
			$conditions = trim(substr($conditions, 5));
		}
		$this->__query[$qkey]['QUICK_WHERE'] = $conditions;
		return $this;
	}

	# ###########################################################################

	/**
	* Internal method for preparing SQL WHERE and HAVING statements
	*
	* @param integer $mode 0 (zero) for WHERE, anything else for HAVING
	* @param string $column The field name used in the HAVING condition statement
	* @param string $operator The logical operator used in the HAVING condition statement
	* @param mixed $value The value used in the HAVING condition statement
	* @param bool $or_mode Set the OR statement
	* @return object (this) HBaseDbQuery
	*/
	protected function __whereHaving($mode = 0, $column_or_aggregate, $operator, $value, $or_mode = false)
	{
		$qkey = $this->__query_key;
		if ($mode == 0) {
			$pkey = 'WHERE';
			if ($qkey != 'DELETE' && $qkey != 'SELECT' && $qkey != 'UPDATE' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
				$this->addError("The SQL query builder is not in DELETE, SELECT, or UPDATE mode", E_USER_WARNING);
				return $this;
			}
		} else {
			$pkey = 'HAVING';
			if ($qkey != 'SELECT' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
				$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
				return $this;
			}
		}
		// Check the function agruments
		if (!is_string($column_or_aggregate) || trim($column_or_aggregate) == '') {
			if ($pkey == 'WHERE') {
				$this->addError("Invalid WHERE column parameter type", E_USER_WARNING);
			} else {
				$this->addError("Invalid HAVING column name or aggregate function name parameter type", E_USER_WARNING);
			}
			return $this;
		}
		if (!is_string($operator) || trim($operator) == '') {
			$this->addError("Invalid {$pkey} operator parameter type", E_USER_WARNING);
			return $this;
		}
		if (!isset($this->__allowed_where_value_types[strtolower(gettype($value))])) {
			$this->addError("Invalid {$pkey} value parameter type", E_USER_WARNING);
			return $this;
		}
		if (is_null($value) || strtoupper($value) == 'NULL') { $value = 'NULL'; }
		// Check the DELETE/SELECT/UPDATE WHERE/HAVING query section
		if (!isset($this->__query[$qkey][$pkey]) || !is_array($this->__query[$qkey][$pkey])) {
			$this->__query[$qkey][$pkey] = array();
		}
		// Init WHERE/HAVING group, if is in OR mode then start a new group
		$i = count($this->__query[$qkey][$pkey]) - 1;
		if ($i < 0) { $i = 0; }
		if ($or_mode) { $i++; }
		if (!isset($this->__query[$qkey][$pkey][$i])) {
			$this->__query[$qkey][$pkey][$i] = array();
		}
		// Adding condition in the WHERE/HAVING query part
		$this->__query[$qkey][$pkey][$i][] = array(
			'LEFT' => trim($column_or_aggregate),
			'OPERATOR' => trim($operator),
			'RIGHT' => $value,
		);
		return $this;
	}

	# ###########################################################################

	/**
	* Internal method for preparing SQL ORDER BY and GROUP BY statements
	*
	* @param integer $mode 0 (zero) for ORDER BY, anything else for GROUP BY
	* @param string $column The field name used in the HAVING condition statement
	* @param bool $descending (false for ascending order, true for descending order)
	* @return object (this) HBaseDbQuery
	*/
	protected function __orderGroupBy($mode = 0, $column, $descending = false)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'SELECT' && $qkey != 'UNION_SELECT_' . $this->__union_index) {
			$this->addError("The SQL query builder is not in SELECT mode", E_USER_WARNING);
			return $this;
		}
		if ($mode == 0) { $pkey = 'ORDER'; }
		else { $pkey = 'GROUP'; }
		// Check the function arguments
		if (!is_string($column) || trim($column) == '') {
			$this->addError("Invalid {$pkey} BY column parameter", E_USER_WARNING);
			return $this;
		}
		$column = trim($column);
		// Check the SELECT ORDER/GROUP BY query section
		if (!isset($this->__query[$qkey][$pkey . '_BY']) || !is_array($this->__query[$qkey][$pkey . '_BY'])) {
			$this->__query[$qkey][$pkey . '_BY'] = array();
		}
		// Adding conditions in the ORDER/GROUP BY query section
		if (!isset($this->__query[$qkey][$pkey . '_BY'][$column])) {
			$this->__query[$qkey][$pkey . '_BY'][$column] = $descending;
		}
		return $this;
	}

	# ###########################################################################

	/**
	* Internal method for preparing SQL INSERT and UPDATE statements
	*
	* @param array $columns_data
	* @param string $target_table The database table name
	* @param string $schema (optional) The database schema name
	* @return object (this) HBaseDbQuery
	*/
	protected function __insertUpdate($columns_data, $target_table, $schema = null)
	{
		$qkey = $this->__query_key;
		if ($qkey != 'INSERT' && $qkey != 'UPDATE') { return $this; }

		if (!is_string($target_table) || trim($target_table) == '') {
			if (!isset($this->__query[$qkey]['TABLE']) || trim($this->__query[$qkey]['TABLE']) == '') {
				$this->addError("Invalid target table name for the $qkey query", E_USER_WARNING);
				return $this;
			}
		} else {
			if (is_string($schema)) {
				$schema = trim($schema);
				if ($schema != '') { $target_table .= $schema . '.' . $target_table; }
			}
			$this->__query[$qkey]['TABLE'] = $target_table;
		}

		if (!isset($this->__query[$qkey]['FIELDS']) || !is_array($this->__query[$qkey]['FIELDS'])) {
			$this->__query[$qkey]['FIELDS'] = array();
		}

		$check_fields = method_exists($this, 'validate_field_value');
		foreach ($columns_data as $field => $value) {
			$field_ok = true;
			$field = trim($field);
			if ($check_fields) {
				$value = $this->validate_field_value($target_table, $field, $value, $schema);
				if ($value === false) { $field_ok = false; }
			}
			if (!$field_ok) {
				$this->addError("Invalid data or field name for the field <i>$field</i> from table <i>$target_table</i>",
					E_USER_WARNING);
			} else {
				$this->__query[$qkey]['FIELDS'][$field] = $value;
			}
		}
		return $this;
	}

	# ###########################################################################

}
